package com.niiwoo.civet.account.service.local.openAccount;

import com.niiwoo.civet.account.constant.AccountRegisterErrorCode;
import com.niiwoo.civet.account.dao.entity.OpenAccountRecord;
import com.niiwoo.civet.account.dto.common.LanMaoGatewayRequestDTO;
import com.niiwoo.civet.account.dto.request.CreateRegisterOrderRequestDTO;
import com.niiwoo.civet.account.enums.OpenAccountRecordStatusEnum;
import com.niiwoo.civet.account.enums.OpenAccountWayEnum;
import com.niiwoo.tripod.lanmao.enums.UserRoleEnum;
import com.niiwoo.tripod.provider.exception.BizException;
import java.util.List;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;

public abstract class AbstractOpenAccountService<T1, T2> {

    public final LanMaoGatewayRequestDTO createOrder(CreateRegisterOrderRequestDTO requestDTO) {
        assertSupportRole(requestDTO.getAccountRole());
        assertSupportWay(requestDTO.getOpenAccountWay());
        return internalCreateOrder(requestDTO);
    }

    abstract protected LanMaoGatewayRequestDTO internalCreateOrder(CreateRegisterOrderRequestDTO requestDTO);

    abstract public T2 updateOrder(T1 t1);

    /**
     * @param s 获取订单操作
     * @param p 校验订单操作
     * @param f1 获取成功结果函数
     * @param f2 获取开户记录
     * @param f3 处理订单函数
     * @param <R> 返回类型
     * @param <T> 订单类型
     */
    protected final <R, T> R doUpdateOrder(Supplier<T> s, Predicate<T> p, Function<T, R> f1, Function<T, OpenAccountRecord> f2, BiFunction<T, OpenAccountRecord, R> f3) {
        // 获取订单
        T order = s.get();
        if (order == null) {
            throw new BizException(AccountRegisterErrorCode.ACCOUNT_REGISTER_ORDER_NOT_EXISTS);
        }
        // 校验订单
        if (p.test(order)) {
            return f1.apply(order);
        }
        // 开户记录是否存在
        OpenAccountRecord record = f2.apply(order);
        if (record == null) {
            throw new BizException(AccountRegisterErrorCode.ACCOUNT_REGISTER_RECORD_NOT_EXISTS);
        }
        // 是否成功
        if (OpenAccountRecordStatusEnum.except(record.getStatus(), OpenAccountRecordStatusEnum.SUCCESS)) {
            return f1.apply(order);
        }
        return f3.apply(order, record);
    }


    protected final void assertSupportRole(UserRoleEnum role) {
        if (!getSupportRole().contains(role)) {
            throw new BizException(AccountRegisterErrorCode.NOT_SUPPORT_ROLE);
        }
    }

    abstract protected List<UserRoleEnum> getSupportRole();

    protected final void assertSupportWay(OpenAccountWayEnum way) {
        if (!getSupportWay().contains(way)) {
            throw new BizException(AccountRegisterErrorCode.UNSUPPORT_OPEN_ACCOUNT_WAY);
        }
    }

    abstract protected List<OpenAccountWayEnum> getSupportWay();

}
